package org.pfc.porlapatilla.util;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.imgscalr.Scalr;

/**
 * This class provides some methods related to images. It uses {@link Scalr}
 * <code>class</code> to resize images.
 * 
 * @author jorgepolobermudez
 * 
 */
public class ImageUtil {

    public enum ImageFormat {
	JPG("jpg"), PNG("png"), GIF("gif");

	public final String value;

	ImageFormat(String format) {
	    this.value = format;
	}
    }

    public static BufferedImage crop(BufferedImage src, int size) {
	return crop(src, size, size);
    }

    public static BufferedImage crop(BufferedImage src, int width, int height) {
	int x = src.getWidth() / 2 - width / 2;
	int y = src.getHeight() / 2 - height / 2;

	// System.out.println("--- " + src.getWidth() + " - " + src.getHeight()
	// + " - " + x + " - " + y);

	BufferedImage clipping = new BufferedImage(width, height,
		BufferedImage.TYPE_INT_RGB);
	Graphics2D area = (Graphics2D) clipping.getGraphics().create();
	area.drawImage(src, 0, 0, clipping.getWidth(), clipping.getHeight(), x,
		y, x + clipping.getWidth(), y + clipping.getHeight(), null);
	area.dispose();

	return clipping;
    }

    /**
     * Creates a square thumbnail
     * 
     * @param src
     * @param squareSize
     *            - The size of the square
     * @return
     */
    public static BufferedImage createThumbnail(BufferedImage src,
	    int squareSize) {
	BufferedImage resized = Scalr.resize(src, squareSize);

	int w = resized.getWidth();
	int h = resized.getHeight();

	int size = Math.min(w, h);

	return crop(resized, size);
    }

    /**
     * Loads an image from a given byte array
     * 
     * @param bytes
     * @return
     * @throws IOException
     *             - if an error occurs during reading
     */
    public static BufferedImage loadFile(byte[] bytes) throws IOException {
	InputStream is = new ByteArrayInputStream(bytes);

	return ImageIO.read(is);
    }

    /**
     * Loads an image from a given file
     * 
     * @param f
     * @return
     * @throws IOException
     *             - if an error occurs during reading
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static BufferedImage loadFile(File f) throws IOException {
	BufferedImage bImage = ImageIO.read(f);
	return bImage;
    }

    /**
     * Loads an image from a given file name
     * 
     * @param fileName
     * @return
     * @throws IOException
     *             - if an error occurs during reading
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static BufferedImage loadFile(String fileName) throws IOException {
	if (fileName == null || fileName.length() == 0) {
	    throw new IllegalArgumentException(
		    "File name is null or zero length");
	}

	File f = new File(fileName);
	return loadFile(f);
    }

    /**
     * Saves an image to a given file
     * 
     * @param image
     * @param outputFile
     * @throws IOException
     *             - if an error occurs during writing
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static void saveImage(BufferedImage image, File outputFile)
	    throws IOException {
	saveImage(image, outputFile, ImageFormat.JPG.value);
    }

    /**
     * Saves an image to a given file name
     * 
     * @param image
     * @param outFileName
     * @throws IOException
     *             - if an error occurs during writing
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static void saveImage(BufferedImage image, String outFileName)
	    throws IOException {
	saveImage(image, outFileName, ImageFormat.JPG.value);
    }

    /**
     * Saves an image to a given file with the given format
     * 
     * @param image
     * @param outputFile
     * @param format
     * @throws IOException
     *             - if an error occurs during writing
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static void saveImage(BufferedImage image, File outputFile,
	    String format) throws IOException {

	if (image == null) {
	    throw new IllegalArgumentException("Image is null");
	}
	if (outputFile == null) {
	    throw new IllegalArgumentException("File is null");
	}
	if (format == null || format.length() == 0) {
	    throw new IllegalArgumentException("Format is null or zero length");
	}

	ImageIO.write(image, format, outputFile);
    }

    /**
     * Saves an image to a given file name with the given format
     * 
     * @param image
     * @param outFileName
     * @param format
     * @throws IOException
     *             - if an error occurs during writing
     * @throws IllegalArgumentException
     *             - if any parameter is null or zero length
     */
    public static void saveImage(BufferedImage image, String outFileName,
	    String format) throws IOException {

	if (outFileName == null || outFileName.length() == 0) {
	    throw new IllegalArgumentException(
		    "File name is null or zero length");
	}

	File f = new File(outFileName);
	saveImage(image, f, format);
    }

    /**
     * Converts an image to byte array. The image is represented by the given
     * file name.
     * 
     * @param fileName
     * @return
     * @throws IOException
     */
    public static byte[] toBytes(String fileName) throws IOException {
	if (fileName == null || fileName.length() == 0) {
	    throw new IllegalAccessError("File name is null or zero length");
	}

	File f = new File(fileName);
	return toBytes(f);
    }

    /**
     * Converts an image to byte array. The image is represented by the given
     * file.
     * 
     * @param f
     * @return
     * @throws IOException
     */
    public static byte[] toBytes(File f) throws IOException {
	BufferedImage image = loadFile(f);
	ByteArrayOutputStream baos = new ByteArrayOutputStream();

	ImageIO.write(image, ImageFormat.JPG.value, baos);
	baos.flush();
	byte[] bytes = baos.toByteArray();
	baos.close();

	return bytes;
    }
}
